#!/usr/bin/env bash
# The purpose of this script is to release the current version by creating and pushing a tag

REMOTE='origin'

# Ensure that the script is being run from the root project directory
PROPERTIES_FILE='gradle.properties'
if [ ! -f "$PROPERTIES_FILE" ]; then
  echo "Could not find $PROPERTIES_FILE, please run this script from the root project directory."
  exit 2
fi

# Process CLI arguments
TARGET="HEAD"
for ARG in "$@"; do
  if [ "$ARG" = '-h' ] || [ "$ARG" = '--help' ]; then
    cat ./scripts/help-text/release.txt
    exit 0
  else
    TARGET="$ARG"
  fi
done

# Determine and verify the target commit
TARGET_COMMIT=`git rev-parse --verify $TARGET`
if [ $? != 0 ]; then
  echo "Invalid target: $TARGET"
  echo ''
  cat ./scripts/help-text/release.txt
  exit 2
fi

# Abort if there are uncommitted changes in the properties file
if [ "$(git diff -- $PROPERTIES_FILE)" ]; then
  echo "There are uncommitted changes in $PROPERTIES_FILE, please try again once all your changes are committed."
  exit 1
fi

# Determine version to be released
VERSION=`awk 'BEGIN { FS = "=" }; $1 == "version" { print $2 }' $PROPERTIES_FILE | awk '{ print $1 }'`
if [ -z "$VERSION" ]; then
  echo "Could not read the version from $PROPERTIES_FILE, please fix it and try again."
  exit 1
fi

# Determine if the version is a release candidate version
RELEASE_CANDIDATE=false
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then
  RELEASE_CANDIDATE=true
fi

# Ensure that the target commit is an ancestor of master
git merge-base --is-ancestor $TARGET_COMMIT master
if [ $? != 0 ]; then
  if $RELEASE_CANDIDATE; then
    # Since this is a release candidate, allow it with a warning and confirmation
    echo -n "You're attempting to publish a release candidate from a non-master branch. Are you sure you want to do this? (y/N) "
    read ANSWER
    if [[ ! "$ANSWER" =~ ^[yY]+$ ]]; then
      echo 'Aborting...'
      exit 1
    fi
  else
    # In the general case, don't allow it
    echo "Invalid target: $TARGET"
    echo 'Please select a target commit which is an ancestor of master.'
    exit 1
  fi
fi

# Update local tags
echo -n 'Updating local tags via remote fetch... '
git fetch origin > /dev/null 2>&1
echo 'done'

# Perform some release candidate assertions, if applicable
if $RELEASE_CANDIDATE; then
  SUFFIXLESS_VERSION=${VERSION%-*}
  # Assert that this release candidate precedes the associated release
  if [ "$(git tag --list v$SUFFIXLESS_VERSION)" ]; then
    echo "Cannot create release candidate $VERSION, as a release for $SUFFIXLESS_VERSION already exists."
    echo "Release candidates must come before proper releases, so please bump the project version in $PROPERTIES_FILE and try again."
    exit 1
  fi
  # Assert that there exists no available lower RC number (e.g. don't allow 1.2.3-rc.2 if 1.2.3-rc.1 is available)
  RC_NUMBER=1
  while true; do
    RC_VERSION="$SUFFIXLESS_VERSION-rc.$RC_NUMBER"
    # Break once we've reached the current RC number
    if [ "$VERSION" = "$RC_VERSION" ]; then break; fi
    # If this lower RC number is available, fail and suggest the user to use this RC number instead
    if [ -z "$(git tag --list "v$RC_VERSION")" ]; then
      echo "Cannot create release candidate $VERSION, as $RC_VERSION doesn't exist."
      echo "Please try again using $RC_VERSION as the project version in $PROPERTIES_FILE."
      exit 1
    fi
    let 'RC_NUMBER++'
  done
fi

# Ensure that release tag name wouldn't conflict with a local branch
TAG_NAME="v$VERSION"
git show-ref --verify refs/heads/$TAG_NAME > /dev/null 2>&1
if [ $? = 0 ]; then
  echo "Cannot create tag $TAG_NAME, as it would conflict with a local branch of the same name."
  echo 'Please delete this branch and avoid naming branches like this in the future.'
  echo "Hint: 'git branch -D $TAG_NAME' (WARNING: you will lose all local changes on this branch)"
  exit 1
fi

# Create release tag
git tag -a $TAG_NAME $TARGET_COMMIT -m "$TAG_NAME"
if [ $? != 0 ]; then
  echo "Could not create tag $TAG_NAME"
  exit 1
else
  echo "Created tag $TAG_NAME at commit $TARGET_COMMIT ($TARGET)"
fi

# Push release tag
echo "Pushing tag $TAG_NAME..."
git push $REMOTE $TAG_NAME

if [ $? != 0 ]; then
  echo 'Push failed, clearing tag from local repo...'
  git tag -d $TAG_NAME
  exit 1
fi

echo "Tag push complete. You can view the $TAG_NAME publish job here: https://github.com/linkedin/rest.li/actions/workflows/publish.yml"
